package com.tyrone.concurrent.lock;

import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 有界队列： 队列为满的时候，add()阻塞，队列为空时，remove()阻塞
 *
 * @author Tyrone
 * @date 2021/12/20 14:12
 */
public class BoundedQueue<T> {

    private Object[] items;

    private int addIndex, removeIndex, count;
    //用于线程的同步控制
    private Lock lock = new ReentrantLock();
    private Condition notEmpty = lock.newCondition();
    private Condition notFull = lock.newCondition();

    /**
     * 初始化大小
     *
     * @param size
     */
    public BoundedQueue(int size) {
        items = new Object[size];
    }

    /**
     * 有界队列添加元素
     *
     * @param t
     * @throws InterruptedException
     */
    public void add(T t) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length)
                notFull.await(); // 释放lock 锁，因为notFull依赖于lock，所以释放的也是lock
            items[addIndex] = t;
            if (++addIndex == items.length)
                addIndex = 0;
            ++count;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 由头部开始删除一个元素，如果数组为空，则进入等待状态，直到由新的元素增加
     * @return
     * @throws InterruptedException
     */
    public T remove() throws InterruptedException{
        lock.lock();
        try {
            while (count == 0)
                notEmpty.await();
            Object x = items[removeIndex];
            if (++removeIndex == items.length)
                removeIndex = 0;
            --count;
            notFull.signal();
            return (T) x;
        }finally {
            lock.unlock();
        }
    }
}
